<?php
/**
 * Created by PhpStorm.
 * User: admin
 * Date: 2019/11/14
 * Time: 14:20
 */

namespace app\adminapiv3\service;


use app\common\service\AttackData;
use app\common\service\HostNormalRuleRelation;
use app\common\service\NetworkAttackDetail;
use app\common\service\ServerDownloadLog;

class NetworkAttack extends Base
{
    /**
     * @name 网络日志列表
     * @param $params
     * @param int $limit
     * @return array
     * @author wx
     * @date 2020/1/4 13:54
     */
    function list($params, $limit = 10)
    {

        $server = new \app\common\service\NetworkAttack();
        $list = $server->list($params, $limit);
        //echo $list;echo '<br>';die;


        if(empty($list['data']))
        {
            return $list;
        }

        $rule_id = [];
        foreach ($list['data'] as $k => $v){
            $where['('.$v['event_id'] . ',' . $v['atime'].')'] = 0;
            $rule_id[] = $v['rule_id'];

            $host[$v['id']] = $k;
        }

        $content = '('.implode(',', array_keys($where)).')';

        $whereCount = '(event_id, atime) in' .$content;

        $field = 'src_port, src_country, src_province, src_city, src_detail,
                dest_port, dest_country, dest_province, dest_city, dest_detail';

        //查询规则详情
        $detailList = db('network_attack_detail')->field($field)->where($whereCount)->column($field, 'event_id');
        //$detailList = db('network_attack_detail')->field($field)->where($whereCount)->select(false);
        //echo $detailList;echo '<br>';


        //查询规则状态
        $ruleStatusList = db('normal_rule')->alias('nr')
            ->join('host_normal_rule_relation hn','nr.id = hn.rule_id','right')
            ->where('sid', 'in', $rule_id)
            ->where('host_id',$params['host_id'])
            ->field('status,sid')
            ->column('status','sid');
//        $ruleStatusList = db('normal_rule')->alias('nr')
//            ->join('host_normal_rule_relation hn','nr.id = hn.rule_id','right')
//            ->where('sid', 'in', $rule_id)
//            ->where('host_id',$params['host_id'])
//            ->field('status,sid')
//            ->select(false);


        $typeServer = new \app\common\service\IpsType();
        $networkType_a = $typeServer->networkList();

        foreach ($list['data'] as $k => $v)
        {
            if(isset($detailList[$v['event_id']])){
                $list['data'][$k] = [
                    'id' => $v['id'],//数据库自增id
                    'host_id' => $v['host_id'],//主机id
                    'description' => $v['description'],//攻击描述

                    'attack_dest' => $v['dest_ip'] . ':' . $detailList[$v['event_id']]['dest_port'] .
                        '(' . $detailList[$v['event_id']]['dest_country'] . $detailList[$v['event_id']]['dest_province'] .
                        $detailList[$v['event_id']]['dest_city'] . $detailList[$v['event_id']]['dest_detail'] . ')', //攻击目标 (为了兼容前端命名!!!!!!)

                    'attack_src' => $v['src_ip'] . ':' . $detailList[$v['event_id']]['src_port'] . '(' . $detailList[$v['event_id']]['src_country']
                        . $detailList[$v['event_id']]['src_province'] . $detailList[$v['event_id']]['src_city']
                        . $detailList[$v['event_id']]['src_detail'] . ')', //攻击来源 (为了兼容前端命名!!!!!!)

                    'domain_name' => $v['domain_name'],//攻击域名
                    'url' => $v['url'],//攻击URL
                    'atime' => date('Y-m-d H:i:s', $v['atime']),//攻击时间
                    'ctime' => $v['ctime'],//日志创建时间
                    'type' => $networkType_a[$v['type']],//攻击类型
                    'level' => $this->dangerLevel2string($v['level']),//危险等级
                    'handle' => $this->handle2string($v['handle']),//处理方式
                    'rule_id' => $v['rule_id'],//对应规则id
                    'allow_ip_rule_id' => $v['allow_ip_rule_id'],//设置ip白名单
                    'event_id' => $v['event_id'],//客户端事件id
                    'status' => $ruleStatusList[$v['rule_id']],//规则状态
                    'src_ip' => $v['src_ip'],//来源ip
                ];
            }else{
                $list['data'][$k] = [
                    'id' => $v['id'],//数据库自增id
                    'host_id' => $v['host_id'],//主机id
                    'description' => $v['description'],//攻击描述
                    'attack_dest' => $v['dest_ip'] . '( 无法获取 )',
                    'attack_src' => $v['src_ip'] .'( 无法获取 )',
                    'domain_name' => $v['domain_name'],//攻击域名
                    'url' => $v['url'],//攻击URL
                    'atime' => date('Y-m-d H:i:s', $v['atime']),//攻击时间
                    'ctime' => $v['ctime'],//日志创建时间
                    'type' => $networkType_a[$v['type']],//攻击类型
                    'level' => $this->dangerLevel2string($v['level']),//危险等级
                    'handle' => $this->handle2string($v['handle']),//处理方式
                    'rule_id' => $v['rule_id'],//对应规则id
                    'allow_ip_rule_id' => $v['allow_ip_rule_id'],//设置ip白名单
                    'event_id' => $v['event_id'],//客户端事件id
                    'status' => $ruleStatusList[$v['rule_id']],//规则状态
                    'src_ip' => $v['src_ip'],//来源ip
                ];
            }
        }


        return $list;
    }

    function indexData()
    {
        //类型
        $typeServer = new \app\common\service\IpsType();
        $type = $typeServer->networkList();
        foreach($type as $k => $value){
            $a['id'] = $k;
            $a['value'] = $value;
            $data['type'][] = $a;
        }

        //处理方式
        $data['handle'] = array(
                array('id' => 1, 'value' => '警告'),
                array('id' => 32, 'value' => '通过'),
                array('id' => 0, 'value' => '拒绝'),
        );

        return $data;
    }

    /**
     * @name 等级转化为字符串
     * @param $level 1极高 2高 3中 4低
     * @author wx
     * @date 2019/11/15 10:45
     */
    function dangerLevel2string($level)
    {
        $levelArr = array(
            1 => '极高',
            2 => '高',
            3 => '中',
            4 => '低',
        );

        $levelStr = isset($levelArr[$level]) ? $levelArr[$level] : '未知';
        return $levelStr;
    }


    /**
     * @name 处理方式
     * @param $handle
     * @return mixed|string
     * @author wx
     * @date 2019/11/15 10:52
     */
    function handle2string($handle)
    {
        $handleArr = array(
            '1' => '警告',
            '32' => '通过'
        );

        $handleStr = isset($handleArr[$handle]) ? $handleArr[$handle] : '拒绝';

        return $handleStr;
    }

    function allowIp($host_id, $id, $src_ip)
    {
        //1. 将攻击来源ip添加一条自定义规则
        $server = new \app\common\service\NetworkAttack();
        $info = $server->findData(['id' => $id, 'src_ip' => $src_ip, 'allow_ip_rule_id' => 0],'host_id, src_ip');

        if(empty($info)){
            $this->setError($this->CODE_FAIL, '该规则已设置了IP白名单,请勿重复设置');
            return false;
        }

        $type = 11;//IP限制;
        $data = [
            'description' => '网络日志设置白名单',
            'content' => $src_ip,
            'status' => 1,
            'handle' => 1,
            'type' => $type,
            'intranet' => 0,
            'execute_content' => '',
            'ctime' => time(),
            'name' => '设置白名单',
            'host_id' => $host_id
        ];

        $ipsRuleDb = new \app\common\service\IpsRule();
        //查询是否有相同规则

        $insertId = $ipsRuleDb->add($data);
        $ipsRuleServer = new IpsRule();
        $updateData = [
            'execute_content' => $ipsRuleServer->encryptRule($insertId, $data, $type)
        ];
        //修改
        $ipsRuleDb->modify(['host_id' => $host_id, 'id' => $insertId], $updateData);


        //2. 将所有相同来源ip的数据都设置为已设置
        $update = array(
            'allow_ip_rule_id' => $insertId,
        );

        $server->modify(['host_id' => $host_id, 'src_ip' => $src_ip], $update);

        return true;
    }

    /**
     * @name 取消白名单
     * @param $host_id
     * @param $rule_id
     * @author wx
     * @date 2020/1/3 16:26
     */
    function closeAllowIp($host_id, $id)
    {
        //1. 查询当前日志
        $server = new \app\common\service\NetworkAttack();
        $info =$server->findData(['id' => $id],'id, allow_ip_rule_id,src_ip');
        if(empty($info)){
            $this->setError($this->CODE_FAIL, '未查询到此日志');
            return false;
        }


        //1. 删除规则
        $ipRuleServer = new \app\common\service\IpsRule();

        $ipRuleServer->del(['host_id' => $host_id, 'id' => $info['allow_ip_rule_id']]);

        //2. 改变network_attack数据
        $networkAttackServer = new \app\common\service\NetworkAttack();
        $networkAttackServer->modify(['host_id' => $host_id, 'allow_ip_rule_id' => $info['allow_ip_rule_id'],'src_ip' => $info['src_ip']], ['allow_ip_rule_id' => 0]);

        return true;
    }

    /**
     * @name 停用规则
     * @param $id
     * @author wx
     * @date 2019/11/15 15:54
     */
    function close($host_id, $id)
    {
        $server = new \app\common\service\NetworkAttack();
        $networkInfo = $server->findData(['id' => $id],'rule_id,host_id');


        if(empty($networkInfo)){
            $this->setError($this->CODE_FAIL,'参数错误!');
            return false;
        }

        $condition = array(
            'host_id' => $networkInfo['host_id'],
            'sid' => $networkInfo['rule_id']
        );
        $hostNormalRelation = new HostNormalRuleRelation();
        $relationInfo = $hostNormalRelation->findSidData($condition,'hn.id');

        if(empty($relationInfo)){
            $this->setError($this->CODE_FAIL,'未查询到规则!');
            return false;
        }

        $hostNormalRelation->modify(['host_id' => $host_id, 'id' => $relationInfo['id']], ['status' => 0]);

        return true;
    }

    /**
     * @name 启用规则
     * @param $host_id
     * @param $id
     * @return bool
     * @author wx
     * @date 2020/1/3 16:36
     */
    function open($host_id, $id)
    {
        $server = new \app\common\service\NetworkAttack();
        $networkInfo = $server->findData(['id' => $id],'rule_id,host_id');

        if(empty($networkInfo)){
            $this->setError($this->CODE_FAIL,'参数错误!');
            return false;
        }

        $condition = array(
            'host_id' => $networkInfo['host_id'],
            'sid' => $networkInfo['rule_id']
        );
        $hostNormalRelation = new HostNormalRuleRelation();
        $relationInfo = $hostNormalRelation->findSidData($condition,'hn.id');

        if(empty($relationInfo)){
            $this->setError($this->CODE_FAIL,'未查询到规则!');
            return false;
        }

        $hostNormalRelation->modify(['host_id' => $host_id, 'id' => $relationInfo['id']], ['status' => 1]);

        return true;
    }

    /**
     * @name 下载数据包
     * @param $id
     * @return bool
     * @author wx
     * @date 2020/1/4 13:45
     */
    function downloadData($id)
    {
        $server = new \app\common\service\NetworkAttack();
        $networkInfo = $server->findData(['id' => $id],'event_id, atime');


        if(empty($networkInfo)){
            $this->setError($this->CODE_FAIL,'参数错误!');
            return false;
        }

        $condition = array(
            'event_id' => $networkInfo['event_id'],
            'atime' => $networkInfo['atime'],
        );
        $attackDataServer = new AttackData();
        $dataInfo = $attackDataServer->findAllDataPackage($condition);


        if(empty($dataInfo)){
            $this->setError($this->CODE_FAIL,'没有查询到此数据包!');
            return false;
        }

        $dir = 'download/network/dataPackage/';
        if (!file_exists($dir)) {
            mkdir($dir,0777, true);
        }

        $fileName = $id . '_' . $networkInfo['atime'] . '.txt';

        $content = '';
        foreach ($dataInfo as $k => $value){
            $content .= base64_decode($value['data_package']) .PHP_EOL;
        }


        //生成文件
        file_put_contents($dir.$fileName, $content);

        //2. 加入下载记录
        $userInfo = $this->getUserInfo();
        $addData = array(
            'download_id' => $networkInfo['event_id'],
            'user_id' => $userInfo['id'],
            'module' => 8,
            'path' => $dir.$fileName,
            'ip' => $_SERVER['REMOTE_ADDR'],
            'ctime' => time()
        );

        $serverDownloadLog = new ServerDownloadLog();
        $serverDownloadLog->add($addData);

        $returnData['path'] = $dir.$fileName;
        $returnData['ip'] = $_SERVER['SERVER_ADDR'];
        $returnData['port'] = $_SERVER['SERVER_PORT'];

        return $returnData;
    }


}